package luj.tool.jnproxyan.proxy.network.direct;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import luj.cluster.api.actor.Tellable;
import luj.tool.jnproxyan.proxy.network.direct.state.P2sConn;
import luj.tool.jnproxyan.proxy.network.direct.state.P2sConnAttr;
import luj.tool.jnproxyan.proxy.network.logger.Proxy2sLogger;
import luj.tool.jnproxyan.proxy.network.socks.actor.root.message.http.proxy2s.receive.read.P2sRecvReadMsg;
import luj.tool.jnproxyan.proxy.network.socks.actor.root.message.request.disconnect.P2sDisconnectMsg;
import luj.tool.jnproxyan.framework.proxy.actor.tell.ActorTeller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.OutputStream;

@Component
final class DirectHandler extends SimpleChannelInboundHandler<ByteBuf> {

  public DirectHandler inject(Tellable socksRef) {
    var result = new DirectHandler();
    result._socksRef = socksRef;
    result._actorTeller = _actorTeller;
    return result;
  }

  /**
   * @see luj.tool.jnproxyan.proxy.network.socks.actor.root.message.request.disconnect.OnP2sDisconnect#onHandle
   */
  @Override
  public void channelInactive(ChannelHandlerContext ctx) throws IOException {
    P2sConn conn = new P2sConnAttr(ctx.channel()).get();
    Long socksId = conn.getSocksId();

    new Proxy2sLogger(LOG, socksId).log("与<站>断开");
    conn.getHttpsCli().close();

    _actorTeller.inject(_socksRef).tell(P2sDisconnectMsg.class, (b, m) -> b
        .f(m::reqId).set(socksId)
    );
  }

  @Override
  protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
    P2sConn conn = new P2sConnAttr(ctx.channel()).get();
    Long socksId = conn.getSocksId();
    int byteCount = msg.readableBytes();
    new Proxy2sLogger(LOG, socksId).log2p("收到<站>B，大小：{}", byteCount);

    OutputStream receiving = conn.getHttpsCli().receiveBytesFrom();
    while (msg.isReadable()) {
      receiving.write(msg.readByte());
    }
    receiving.flush();

    _actorTeller.inject(_socksRef).tell(P2sRecvReadMsg.class, (b,m)->b
        .f(m::socksId).set(socksId)
        .f(m::byteCount).set(byteCount)
    );
  }

  private static final Logger LOG = LoggerFactory.getLogger(DirectHandler.class);

  Tellable _socksRef;

  @Autowired
  ActorTeller _actorTeller;
}
